////////////////////////////////////////////////////////////////////////////////////////////////////
//
//	Crytek Character Animation source code
//	
//	History:
//	10/9/2004 - Created by Ivo Herzeg <ivo@crytek.de>
//
//  Contains:
//  default-model joint of the skeleton   
/////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef _CRY_MODELJOINT
#define _CRY_MODELJOINT

// this class contains the information that's common to all instances of bones
// in the given model: like bone name, and misc. shared properties
class CModelJoint
{
public:

	CModelJoint() 
	{
		m_nJointCRC32				=	0;
		m_nJointCRC32Lower	=	0;
		m_CGAObject					=	0;
		m_NodeID						= ~0;
		m_numChildren				=	0x55aa55aa;

		m_idx						=	-1;  //index-counter of this joint 
		m_idxParent			=	-1;	 //index of  parent-joint	
		m_numLevels			=  0;
		m_ObjectID			= -1;

		m_PhysInfo[0].pPhysGeom = 0;
		m_PhysInfo[1].pPhysGeom = 0;
		m_fMass = 0.0f;
		m_CRC32Name=0;

		m_qDefaultRelPhysParent[0].SetIdentity();
		m_qDefaultRelPhysParent[1].SetIdentity();
	}

	~CModelJoint ();


	void SetNameChar(const char * name)
	{
		m_Name = name; 
		assert (strlen(name) < MAX_STATIC_CHARS);
		char pStringArray[MAX_STATIC_CHARS];
		NameCRCHelper::MakeLowercase(pStringArray, name);
		m_CRC32Name = gEnv->pSystem->GetCrc32Gen()->GetCRC32Lowercase(pStringArray); 
	}


	const char * GetJointName() const { return m_Name.c_str(); };
	uint32 GetJointNameHash() const { return m_CRC32Name; }

	void SetJointName(const char* szName) 
	{
		SetNameChar(szName); 

		static const char *g_arrLimbNames[4] = { "L UpperArm","R UpperArm","L Thigh","R Thigh" };
		m_nLimbId = -1;
		for (int j=0; j < SIZEOF_ARRAY(g_arrLimbNames) ;j++)
		{
			if (strstr(szName,g_arrLimbNames[j]))
			{
				m_nLimbId = j;
				break;
			}
		}
	}


	uint32 numChildren ()const {return m_numChildren;}
	int getFirstChildIndexOffset() const {return m_nOffsetChildren;}


	bool qhasParent() const 
	{
		return m_idxParent != -1;
	}
	int getParentIndexOffset() const 
	{
		if (m_idxParent<0)
			return 0;
		int32 offset = m_idxParent-m_idx;		
		return offset;
	}

	CModelJoint* getParent () 
	{
		if (m_idxParent<0)
			return 0;

		int32 offset = m_idxParent-m_idx;		
		assert(offset);
		return (this+offset);
	}
	const CModelJoint* getParent () const  
	{
		if (m_idxParent<0)
			return 0;
		int32 offset = m_idxParent-m_idx;		
		assert(offset);
		return (this+offset);
	}


	int getLimbId () const {return m_nLimbId;}

	const CryBonePhysics& getPhysInfo (int nLod) const {return m_PhysInfo[nLod];}
	CryBonePhysics& getPhysInfo (int nLod) { return m_PhysInfo[nLod]; }

	// updates this bone physics, from the given entity descriptor, and of the given lod
	void UpdatePhysics (const BONE_ENTITY& entity, int nLod);

	void setPhysics (int nLod, const CryBonePhysics& BonePhysics)
	{
		assert (nLod >= 0 && nLod < sizeof(m_PhysInfo)/sizeof(m_PhysInfo[0]));
		m_PhysInfo[nLod] = BonePhysics;
	}

	// the physics for the given LOD is not available
	void resetPhysics (int nLod)
	{
		assert (nLod >= 0 && nLod < sizeof(m_PhysInfo)/sizeof(m_PhysInfo[0]));
		memset (&m_PhysInfo[nLod], 0, sizeof(m_PhysInfo[nLod]));
	}
	const CryBonePhysics& getPhysics (int nLod) const
	{
		assert (nLod >= 0 && nLod < sizeof(m_PhysInfo)/sizeof(m_PhysInfo[0]));
		return m_PhysInfo[nLod];
	}

	// scales the bone with the given multiplier
	void scale (f32 fScale);

	//! Performs post-initialization. This step is requred to initialize the pPhysGeom of the bones
	//! After the bone has been loaded but before it is first used. When the bone is first loaded, pPhysGeom
	//! is set to the value equal to the chunk id in the file where the physical geometry (BoneMesh) chunk is kept.
	//! After those chunks are loaded, and chunk ids are mapped to the registered physical geometry objects,
	//! call this function to replace pPhysGeom chunk ids with the actual physical geometry object pointers.
	//!	NOTE:
	//!	The entries of the map that were used are deleted
	typedef std::map<INT_PTR, struct phys_geometry*> ChunkIdToPhysGeomMap;


	CModelJoint* getChild (unsigned i) {assert(i < numChildren()); return this + m_nOffsetChildren + i;}
	const CModelJoint* getChild (unsigned i) const {assert(i < numChildren()); return this + m_nOffsetChildren + i;}



	void PostInitialize(const Skeleton::CPoseData& poseData);
	Quat &getqRelPhysParent(int nLod) { return m_qDefaultRelPhysParent[nLod]; }

	// updates the given lod level bone physics info from the bones found in the given chunk
	void UpdateHierarchyPhysics (const BONEANIM_CHUNK_DESC* pChunk, unsigned nChunkSize, int nLodLevel);
	//void UpdateHierarchyPhysics( std::vector<BONE_ENTITY> arrBoneEntities );
	void UpdateHierarchyPhysics( DynArray<BONE_ENTITY> arrBoneEntities, int nLod );

	typedef std::map<unsigned, CModelJoint*> UnsignedToCryBoneMap;
	// adds this bone and all its children to the given map controller id-> bone ptr
	void AddHierarchyToControllerIdMap (UnsignedToCryBoneMap& mapControllerIdToCryBone);

	//! Performs post-initialization. This step is requred to initialize the pPhysGeom of the bones
	//! After the bone has been loaded but before it is first used. When the bone is first loaded, pPhysGeom
	//! is set to the value equal to the chunk id in the file where the physical geometry (BoneMesh) chunk is kept.
	//! After those chunks are loaded, and chunk ids are mapped to the registered physical geometry objects,
	//! call this function to replace pPhysGeom chunk ids with the actual physical geometry object pointers.
	//!	NOTE:
	//!	The entries of the map that were used are deleted
	//	typedef std::map<int, struct phys_geometry*> ChunkIdToPhysGeomMap;
	bool PostInitPhysGeom ( ChunkIdToPhysGeomMap& mapChunkIdToPhysGeom, int nLodLevel, bool bAllowRopePhys);

	//--------------------------------------------------------------------------------
	//--------------------------------------------------------------------------------
	//--------------------------------------------------------------------------------
	_smart_ptr<IStatObj> m_CGAObject;			//Static object controlled by this joint.
	int32 m_nOffsetChildren;		// this is 0 if there are no children

	// The whole hierarchy of bones is kept in one big array that belongs to the ModelState
	// Each bone that has children has its own range of bone objects in that array,
	// and this points to the beginning of that range and defines the number of bones.
	uint32	m_NodeID;  //CGA-node
	uint32	m_numChildren;

	int16	  m_idx;
	int16		m_idxParent;	//index of parent-joint. if the idx==-1 then this joint is the root. Usually this values are > 0
	uint16  m_numLevels;
	uint16	m_ObjectID;
	uint32	m_nJointCRC32;      //unique ID of bone (case sensitive)
	uint32	m_nJointCRC32Lower; //unique ID of bone (lower case)

	//physics info for different lods
	// lod 0 is the physics of alive body, 
	// lod 1 is the physics of a dead body
	CryBonePhysics m_PhysInfo[2]; 
	f32 m_fMass;
	int	m_nLimbId; // set by model state class
	Quat m_qDefaultRelPhysParent[2];

	string m_Name;		// the name of the animation (not the name of the file) - unique per-model
	uint32 m_CRC32Name;			//hash value for searching animations


	size_t SizeOfJoint() const
	{
		unsigned nSize = m_Name.capacity();
		return nSize;
	}

	void GetMemoryUsage( ICrySizer *pSizer ) const
	{
		pSizer->AddObject(m_CGAObject);
		pSizer->AddObject(m_Name);
	}

}_ALIGN(128);

#endif
